﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tesla.Graphics;
using Tesla.Math;
using Tesla.Content;
using Tesla.Scene.Shape;
using Tesla.Scene;
using Tesla.Core;
using System.Runtime.InteropServices;
using Tesla.Scene.Extension;

namespace TeslaSamples.Effects {
    /// <summary>
    /// Wireframe rendering based on the method described here: http://www2.imm.dtu.dk/~jab/Wireframe/
    /// </summary>
    [AppDescription("Thick Wireframes", PlatformCapabilities.Direct3D10 | PlatformCapabilities.XNA4, "ThickWireframeImage", "ThickWireframeDesc", "ThickWireframeSource")]
    public class ThickWireframe : BasicApp {
        protected override void LoadContent() {
            Window.Title = "Thick Wireframes";
            Mesh teapot = new Teapot("Utah Teapot");
            teapot.SetScale(30f);
            teapot.Translation = new Vector3(0, -50, 0);
            teapot.Material = ContentManager.Load<Material>("LitBasicColor.tem").Clone();
            teapot.Material.SetRenderState(RasterizerState.CullNone);

            Mesh wireframe = CreateWireframeData("Utah Wireframe", teapot.MeshData);
            wireframe.RenderBucketType = RenderBucketType.PostBucket;
            wireframe.Transform.Set(teapot.Transform);

            Material wireMat = new Material("WireMaterial");
            wireMat.LoadEffect(ContentManager.Load<Effect>("Shaders//WireframeEffect.fx").Clone());
            wireMat.SetEngineParameter("WVP", EngineValue.WorldViewProjection);
            wireMat.SetParameter("WinScale", new Vector2(Renderer.CurrentCamera.Viewport.Width / 2, Renderer.CurrentCamera.Viewport.Height / 2));
            wireMat.SetParameter("WireColor", new Vector3(.8f, .1f, .1f));
            wireMat.SetParameter("FillColor", new Vector4(.7f, .8f, .9f, .5f));
            wireMat.SetRenderState(BlendState.AlphaBlendNonPremultiplied);
            wireMat.SetRenderState(RasterizerState.CullNone);
            wireframe.SetMaterial(wireMat);

            RootNode.AddChild(teapot);
            RootNode.AddChild(wireframe);

            RootNode.AddController(new RotateController(Vector3.Up, 25));
        }

        private Mesh CreateWireframeData(String name, MeshData md) {
            if(md.PrimitiveType != PrimitiveType.TriangleList) {
                return null;
            }

            DataBuffer<Vector3> positions = md.Positions;

            if(positions == null) {
                return null;
            }

            DataBuffer<Vector4> pos0 = new DataBuffer<Vector4>(md.IndexCount);
            DataBuffer<Vector3> pos1 = new DataBuffer<Vector3>(md.IndexCount);
            DataBuffer<Vector3> pos2 = new DataBuffer<Vector3>(md.IndexCount);

            Mesh mesh = new Mesh(name);
            Vector3[] tri = new Vector3[3];

            for(int i = 0; i < md.PrimitiveCount; i++) {
                md.GetPrimitive(i, tri);

                pos0.Set(new Vector4(tri[0], 0));
                pos1.Set(tri[1]);
                pos2.Set(tri[2]);

                pos0.Set(new Vector4(tri[1], 1));
                pos1.Set(tri[0]);
                pos2.Set(tri[2]);

                pos0.Set(new Vector4(tri[2], 2));
                pos1.Set(tri[0]);
                pos2.Set(tri[1]);
            }


            mesh.MeshData.UseIndexedPrimitives = false;
            mesh.MeshData.AddBuffer(VertexSemantic.Position, 0, pos0);
            mesh.MeshData.AddBuffer(VertexSemantic.Position, 1, pos1);
            mesh.MeshData.AddBuffer(VertexSemantic.Position, 2, pos2);
            mesh.MeshData.Reconstruct();

            return mesh;
        }
    }
}
